package com.sxg.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxg.config.RabbitMqConfig;
import com.sxg.convert.SxgOrderConvert;
import com.sxg.dao.SxgOrderDao;
import com.sxg.dao.SxgOrderItemDao;
import com.sxg.entity.*;
import com.sxg.enums.OrderStatusEnum;
import com.sxg.enums.ResultCodeEnum;
import com.sxg.query.SxgOrderQuery;
import com.sxg.redis.RedisCache;
import com.sxg.security.pojo.LoginUser;
import com.sxg.service.SxgAddressService;
import com.sxg.service.SxgGoodsInfoService;
import com.sxg.service.SxgOrderService;
import com.sxg.service.SxgStockService;
import com.sxg.utils.SecurityUtils;
import com.sxg.utils.StringUtils;
import com.sxg.utils.code.AjaxResult;
import com.sxg.vo.CloseOrder;
import com.sxg.vo.DeliveryOrder;
import com.sxg.vo.SxgOrderVO;
import com.sxg.vo.req.OrderReqVo;
import com.sxg.vo.resp.OrderItemRespVo;
import com.sxg.vo.resp.OrderRespVo;
import lombok.AllArgsConstructor;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单表
 *
 * @author 浪漫写尽歌谱 3298751420@qq.com
 * @since 1.0.0 2024-03-07
 */
@Service
@AllArgsConstructor
public class SxgOrderServiceImpl extends ServiceImpl<SxgOrderDao, SxgOrderEntity> implements SxgOrderService {

    @Resource
    private SxgOrderItemDao sxgOrderItemDao;

    @Resource
    private SxgStockService sxgStockService;

    @Resource
    private SxgGoodsInfoService sxgGoodsInfoService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SxgOrderDao sxgOrderDao;

    @Resource
    private SxgAddressService sxgAddressService;

    @Resource
    private AmqpTemplate amqpTemplate;

    @Override
    public AjaxResult page(SxgOrderQuery query) {
        if (query.getStatus() == null) {
            return AjaxResult.error("状态不能为空");
        }
        if (query.getLimit() == null) {
            return AjaxResult.error("创建订单时间不能为空");
        }

        Integer pageNum = (query.getPage() - 1) * query.getLimit();

        query = checkStatus(query);

        Integer count = sxgOrderDao.selectByUserIdAndStatusCount(SecurityUtils.getUserId(), query.getTrueStatus());
        Set<Long> goodsIds = sxgOrderDao.selectByUserIdAndStatusGoodsids(SecurityUtils.getUserId(), query.getTrueStatus(), query.getTime(), query.getLimit(), pageNum);
        if (goodsIds == null || goodsIds.isEmpty()) {
            return AjaxResult.success(new ArrayList<>()).put("total", count);
        }
        List<OrderItemRespVo> orderItemRespVos = sxgOrderDao.selectByUserIdAndStatus(goodsIds);
        return AjaxResult.success(getOrderResp(orderItemRespVos)).put("total", count);
    }

    private SxgOrderQuery checkStatus(SxgOrderQuery query) {
        switch (query.getStatus()) {
            case "-1":
                query.setTrueStatus(null);
                break;
            case "0":
                query.setTrueStatus(Collections.singletonList(Integer.parseInt(OrderStatusEnum.CREATE.getCode())));
                break;
            case "1":
                query.setTrueStatus(Arrays.asList(Integer.parseInt(OrderStatusEnum.PAYING.getCode()), Integer.parseInt(OrderStatusEnum.PAYED.getCode()), Integer.parseInt(OrderStatusEnum.DELIVERING.getCode())));
                break;
            case "2":
                query.setTrueStatus(Collections.singletonList(Integer.parseInt(OrderStatusEnum.DELIVERED.getCode())));
                break;
            default:
                query.setTrueStatus(null);
        }
        return query;
    }

    @Override
    public void save(SxgOrderVO vo) {
        SxgOrderEntity entity = SxgOrderConvert.INSTANCE.convert(vo);

        baseMapper.insert(entity);
    }

    @Override
    public void update(SxgOrderVO vo) {
        SxgOrderEntity entity = SxgOrderConvert.INSTANCE.convert(vo);

        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult delete(String id) {
        SxgOrderEntity sxgOrderEntity = getOne(Wrappers.<SxgOrderEntity>lambdaQuery().select(SxgOrderEntity::getOrderId, SxgOrderEntity::getStatus).eq(SxgOrderEntity::getOrderId, id));
        if (sxgOrderEntity == null) {
            return AjaxResult.error("订单不存在");
        }
        if ("0".equals(sxgOrderEntity.getStatus())) {
            close(Long.parseLong(id));
        }
        sxgOrderItemDao.delete(Wrappers.<SxgOrderItemEntity>lambdaQuery().eq(SxgOrderItemEntity::getOrderId, id));
        removeById(id);
        return AjaxResult.success();
    }

    @Transactional
    @Override
    public AjaxResult createOrderAndLockStock(OrderReqVo vo) {

        //解析前端字段
        String goodsIds = vo.getGoodsIds();
        String[] goodsItemList = goodsIds.split(",");
        ArrayList<Long> goodsIdList = new ArrayList<>();
        HashMap<Long, Integer> goodsCountMap = new HashMap<>();
        for (String goodsItem : goodsItemList) {
            String[] item = goodsItem.split(":");
            long goodsId = Long.parseLong(item[0]);
            goodsIdList.add(goodsId);
            goodsCountMap.put(goodsId, Integer.parseInt(item[1]));
        }

        //校验库存并锁库
        List<SxgStockEntity> sxgStockEntities = sxgStockService.list(new QueryWrapper<SxgStockEntity>().lambda().in(SxgStockEntity::getGoodsId, goodsIdList));
        ArrayList<SxgStockEntity> stockEntities = new ArrayList<>();
        for (SxgStockEntity sxgStockEntity : sxgStockEntities) {
            if (StringUtils.isNull(sxgStockEntity)) {
                return AjaxResult.error(ResultCodeEnum.GOODS_NOT_EXIST.getCode(), ResultCodeEnum.GOODS_NOT_EXIST.getMessage());
            }
            //从redis中减库存
            Object stock = stringRedisTemplate.opsForValue().get("sxg:goods:stock:" + sxgStockEntity.getGoodsId());
            //没有则添加到redis中
            if (StringUtils.isNull(stock)) {
                redisCache.setCacheObject("sxg:goods:stock:" + sxgStockEntity.getGoodsId(), sxgStockEntity.getStock() - sxgStockEntity.getStockLocked(), 60 * 60 * 3, TimeUnit.SECONDS);
            }
            Long l = redisCache.minusStock("sxg:goods:stock:" + sxgStockEntity.getGoodsId(), goodsCountMap.get(sxgStockEntity.getGoodsId()));
            if (l == 0) {
                return AjaxResult.error(ResultCodeEnum.GOODS_STOCK_NOT_ENOUGH.getCode(), ResultCodeEnum.GOODS_STOCK_NOT_ENOUGH.getMessage());
            }
            if (sxgStockEntity.getStock() - sxgStockEntity.getStockLocked() < goodsCountMap.get(sxgStockEntity.getGoodsId())) {
                return AjaxResult.error(ResultCodeEnum.GOODS_STOCK_NOT_ENOUGH.getCode(), ResultCodeEnum.GOODS_STOCK_NOT_ENOUGH.getMessage());
            }

            //更新库存
            sxgStockEntity.setStockLocked(sxgStockEntity.getStockLocked() + goodsCountMap.get(sxgStockEntity.getGoodsId()));
            stockEntities.add(sxgStockEntity);
        }
        sxgStockService.updateBatchById(stockEntities);

        //计算价格 并比较价格
        BigDecimal totalPrice = new BigDecimal(0);
        List<SxgGoodsInfoEntity> goodsInfoEntityList = sxgGoodsInfoService.list(new QueryWrapper<SxgGoodsInfoEntity>().select("id", "price").lambda().in(SxgGoodsInfoEntity::getId, goodsIdList));
        for (SxgGoodsInfoEntity sxgGoodsInfoEntity : goodsInfoEntityList) {
            totalPrice = totalPrice.add(sxgGoodsInfoEntity.getPrice().multiply(new BigDecimal(goodsCountMap.get(sxgGoodsInfoEntity.getId()))));
        }
        BigDecimal subtract = totalPrice.subtract(BigDecimal.valueOf(vo.getPayPrice()));
        if (subtract.compareTo(BigDecimal.valueOf(10)) < 0) {
            totalPrice = BigDecimal.valueOf(vo.getPayPrice());
        } else {
            totalPrice = totalPrice.multiply(BigDecimal.valueOf(Math.ceil(Math.random() * 10)));
        }

        //创建订单
        Long userId = SecurityUtils.getUserId();
        SxgOrderEntity sxgOrderEntity = new SxgOrderEntity();
        sxgOrderEntity.setCreateTime(new Date());
        sxgOrderEntity.setStatus(OrderStatusEnum.CREATE.getCode());
        sxgOrderEntity.setPrice(totalPrice.setScale(2, RoundingMode.UP));
        sxgOrderEntity.setAddressInfo(vo.getAddress());
        sxgOrderEntity.setUserId(userId);
        baseMapper.insert(sxgOrderEntity);

        //发送超时关单的消息
        amqpTemplate.convertAndSend(RabbitMqConfig.ORDER_DELAY_EXCHANGE, RabbitMqConfig.ORDER_DELAY_KEY, CloseOrder.builder().orderId(sxgOrderEntity.getOrderId()).build(), message -> {
            message.getMessageProperties().setDelay(300000);
            return message;
        });

        //记录订单下的商品
        ArrayList<SxgOrderItemEntity> itemEntities = new ArrayList<>();
        for (String goodsItem : goodsItemList) {
            String[] item = goodsItem.split(":");
            SxgOrderItemEntity sxgOrderItem = new SxgOrderItemEntity();
            sxgOrderItem.setOrderId(sxgOrderEntity.getOrderId());
            sxgOrderItem.setGoodsId(Long.valueOf(item[0]));
            sxgOrderItem.setCount(Integer.parseInt(item[1]));
            itemEntities.add(sxgOrderItem);
        }
        sxgOrderItemDao.saveBaths(itemEntities);
        return AjaxResult.success().put("orderId", sxgOrderEntity.getOrderId());
    }

    @Transactional
    @Override
    public AjaxResult pay(Long id) {
        //校验订单
        SxgOrderEntity orderEntity = baseMapper.selectOne(new QueryWrapper<SxgOrderEntity>().select("order_id", "status").eq("order_id", id));
        if (StringUtils.isNull(orderEntity) || !orderEntity.getStatus().equals(OrderStatusEnum.CREATE.getCode())) {
            return AjaxResult.error(ResultCodeEnum.ORDER_NOT_EXIST.getCode(), ResultCodeEnum.ORDER_NOT_EXIST.getMessage());
        }

        //查询订单下的商品
        ArrayList<SxgStockEntity> stockEntities = new ArrayList<>();
        List<SxgOrderItemEntity> itemEntities = sxgOrderItemDao.selectList(new QueryWrapper<SxgOrderItemEntity>().lambda().eq(SxgOrderItemEntity::getOrderId, id));
        List<Long> goodsIdList = itemEntities.stream().map(SxgOrderItemEntity::getGoodsId).collect(Collectors.toList());
        List<SxgStockEntity> sxgStockEntities = sxgStockService.list(new QueryWrapper<SxgStockEntity>().lambda().in(SxgStockEntity::getGoodsId, goodsIdList));

        //减库存，解锁库存
        for (SxgOrderItemEntity itemEntity : itemEntities) {
            for (SxgStockEntity sxgStockEntity : sxgStockEntities) {
                //找到对应的商品
                if (sxgStockEntity.getGoodsId().equals(itemEntity.getGoodsId())) {
                    sxgStockEntity.setStock(sxgStockEntity.getStock() - itemEntity.getCount());
                    sxgStockEntity.setStockLocked(sxgStockEntity.getStockLocked() - itemEntity.getCount());
                    stockEntities.add(sxgStockEntity);
                }
            }
        }
        sxgStockService.updateBatchById(stockEntities);

        //更新订单状态
        SxgOrderEntity sxgOrderEntity = new SxgOrderEntity();
        sxgOrderEntity.setPlayTime(new Date());
        sxgOrderEntity.setStatus(OrderStatusEnum.PAYING.getCode());
        update(sxgOrderEntity, new UpdateWrapper<SxgOrderEntity>().eq("order_id", id));

        //发送延迟发货消息
        amqpTemplate.convertAndSend(RabbitMqConfig.ORDER_DELAY_EXCHANGE, RabbitMqConfig.ORDER_DELAY_KEY, DeliveryOrder.builder().orderId(id).build(), message -> {
            message.getMessageProperties().setDelay(60000);
            return message;
        });

        return AjaxResult.success();
    }

    @Transactional
    @Override
    public AjaxResult close(Long orderId) {
        //校验订单
        SxgOrderEntity orderEntity = getById(orderId);
        if (StringUtils.isNull(orderEntity) || orderEntity.getStatus().equals(OrderStatusEnum.CANCEL.getCode()) || orderEntity.getStatus().equals(OrderStatusEnum.DELIVERED.getCode()) || orderEntity.getStatus().equals(OrderStatusEnum.FINISHED.getCode())) {
            return AjaxResult.error(ResultCodeEnum.ORDER_NOT_EXIST.getCode(), ResultCodeEnum.ORDER_NOT_EXIST.getMessage());
        }


        //查询订单下的商品
        ArrayList<SxgStockEntity> stockEntities = new ArrayList<>();
        List<SxgOrderItemEntity> itemEntities = sxgOrderItemDao.selectList(new QueryWrapper<SxgOrderItemEntity>().lambda().eq(SxgOrderItemEntity::getOrderId, orderId));
        List<Long> goodsIdList = itemEntities.stream().map(SxgOrderItemEntity::getGoodsId).collect(Collectors.toList());
        List<SxgStockEntity> sxgStockEntities = sxgStockService.list(new QueryWrapper<SxgStockEntity>().lambda().in(SxgStockEntity::getGoodsId, goodsIdList));

        //加库存
        for (SxgOrderItemEntity itemEntity : itemEntities) {
            for (SxgStockEntity sxgStockEntity : sxgStockEntities) {
                //找到对应的商品
                if (sxgStockEntity.getGoodsId().equals(itemEntity.getGoodsId())) {
                    //订单为创建状态只解锁库存否则为加库存
                    if (orderEntity.getStatus().equals(OrderStatusEnum.CREATE.getCode())) {

                        sxgStockEntity.setStockLocked(sxgStockEntity.getStockLocked() - itemEntity.getCount());
                    } else {
                        sxgStockEntity.setStock(sxgStockEntity.getStock() + itemEntity.getCount());
                    }

                    String key = "sxg:goods:stock:" + sxgStockEntity.getGoodsId();
                    //删除redis中的缓存库存
                    stringRedisTemplate.delete(key);

                    stockEntities.add(sxgStockEntity);
                }
            }
        }
        sxgStockService.updateBatchById(stockEntities);

        //更新订单状态
        SxgOrderEntity sxgOrderEntity = new SxgOrderEntity();
        sxgOrderEntity.setOrderId(orderId);
        sxgOrderEntity.setStatus(OrderStatusEnum.CANCEL.getCode());
        update(sxgOrderEntity, new UpdateWrapper<SxgOrderEntity>().eq("order_id", orderId).eq("status", OrderStatusEnum.CREATE.getCode()));

        return AjaxResult.success();
    }

    @Override
    public AjaxResult receiptOfGoods(Long orderId) {
        //校验订单
        SxgOrderEntity orderEntity = getById(orderId);
        if (StringUtils.isNull(orderEntity) || (!orderEntity.getStatus().equals(OrderStatusEnum.PAYED.getCode()) && !orderEntity.getStatus().equals(OrderStatusEnum.DELIVERING.getCode()))) {
            return AjaxResult.error(ResultCodeEnum.ORDER_NOT_EXIST.getCode(), ResultCodeEnum.ORDER_NOT_EXIST.getMessage());
        }

        //更新订单状态
        SxgOrderEntity sxgOrderEntity = new SxgOrderEntity();
        sxgOrderEntity.setStatus(OrderStatusEnum.DELIVERED.getCode());
        sxgOrderEntity.setOrderId(orderId);
        updateById(sxgOrderEntity);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult search(String text) {
        Long userId = SecurityUtils.getUserId();
        List<OrderItemRespVo> orderItemRespVos = sxgOrderDao.selectSearchByOrderIdAndGoodsName(userId, text + "%");
        return AjaxResult.success(getOrderResp(orderItemRespVos));
    }

    @Override
    public AjaxResult getOrderInfoById(Long id) {
        List<OrderItemRespVo> orderItemRespVos = sxgOrderDao.selectOrderInfoById(SecurityUtils.getUserId(), id);
        OrderRespVo orderRespVo = getOrderResp(orderItemRespVos).get(0);
        String address = orderRespVo.getAddress();
        SxgAddressEntity addressEntity = sxgAddressService.getById(address);
        orderRespVo.setAddress(JSON.toJSONString(addressEntity));
        return AjaxResult.success(orderRespVo);
    }

    private List<OrderRespVo> getOrderResp(List<OrderItemRespVo> orderItemRespVos) {
        Set<Long> orderId = orderItemRespVos.stream().map(OrderItemRespVo::getOrderId).collect(Collectors.toSet());
        return orderId.stream().map(id -> {
            OrderRespVo orderRespVo = new OrderRespVo();
            orderRespVo.setOrderId(id);
            List<OrderItemRespVo> orderItems = orderItemRespVos.stream().filter(o -> id.equals(o.getOrderId())).collect(Collectors.toList());
            orderItems = orderItems.stream().peek(o -> o.setOrderId(null)).collect(Collectors.toList());
            orderRespVo.setOrderItems(orderItems);
            orderRespVo.setStatus(orderItems.get(0).getStatus());
            orderRespVo.setAddress(orderItems.get(0).getAddressInfo());
            orderRespVo.setOrderPrice(orderItems.get(0).getOrderPrice());
            orderRespVo.setPlayTime(orderItems.get(0).getPlayTime());
            orderRespVo.setCloseTime(orderItems.get(0).getCloseTime());
            orderRespVo.setDeliveryTime(orderItems.get(0).getDeliveryTime());
            orderRespVo.setCreateTime(orderItems.get(0).getCreateTime());
            return orderRespVo;
        }).sorted(Comparator.comparing(OrderRespVo::getCreateTime).reversed()).collect(Collectors.toList());
    }


}